package org.zoomdev.zoom.async.aop;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zoomdev.zoom.aop.Interceptor;
import org.zoomdev.zoom.aop.Invoker;
import org.zoomdev.zoom.aop.factory.AnnotationInterceptorFactory;
import org.zoomdev.zoom.async.AsyncService;
import org.zoomdev.zoom.async.annotation.Async;
import org.zoomdev.zoom.common.exceptions.ZoomException;

import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

public final class AsyncMethodAopMaker extends AnnotationInterceptorFactory<Async> {

    private static final Logger log = LoggerFactory.getLogger(AsyncMethodAopMaker.class);
    private final AsyncService service;
    Interceptor interceptorWithFuture = new AsyncMethodInterceptorWithFuture();
    Interceptor interceptor = new AsyncMethodInterceptor();

    public AsyncMethodAopMaker(AsyncService service) {
        this.service = service;
    }


    @Override
    protected void createInterceptor(Async annotation, Class<?> targetClass, Method method, List<Interceptor> interceptors) {
        if (Future.class.isAssignableFrom(method.getReturnType())) {
            interceptors.add(interceptorWithFuture);
        } else {
            interceptors.add(interceptor);
        }
    }

    private class AsyncMethodInterceptorWithFuture implements Interceptor {


        private AsyncMethodInterceptorWithFuture() {

        }

        @Override
        public Object intercept(Invoker invoker, Method method, Object target, Object[] args) throws Throwable {
            /// 仍然是一个future
            return service.submit((Callable) () -> {
                try {
                    Object value = invoker.invoke(target, args);
                    /// 仍然是一个future
                    if (value instanceof Future) {
                        value = ((Future) value).get();
                    }
                    return value;
                } catch (Throwable e) {
                    log.error("执行异步出错", e);
                    throw new ZoomException("执行错误", e);
                }

            });
        }
    }

    private class AsyncMethodInterceptor implements Interceptor {


        private AsyncMethodInterceptor() {

        }

        @Override
        public Object intercept(Invoker invoker, Method method, Object target, Object[] args) throws Throwable {
            service.run(() -> {
                try {
                    invoker.invoke(target, args);
                } catch (Throwable e) {
                    //如果这里出错了怎么办?
                    log.error("执行异步出错", e);
                    throw new ZoomException("执行错误", e);
                }
            });

            return null;
        }
    }


}
